﻿using T0yK4T.IO;
using T0yK4T.Tools;
using System;
using System.Collections.Generic;
using ProtoBuf;

namespace ToyChat.BuiltinModules
{
    /// <summary>
    /// This class can be used by clients to manage / communicate with other users
    /// </summary>
    [ProtoContract(Name = "RemoteUser")]
    public class RemoteUser : IUser
    {
        private List<IChannel> channels = new List<IChannel>();
        private IClient client;

        /// <summary>
        /// Empty constructor - Doesn't do anything
        /// </summary>
        public RemoteUser()
        {
        }

        /// <summary>
        /// Initializes a new instance of <see cref="RemoteUser"/> and copies the values from the specified <see cref="IUser"/> instance
        /// </summary>
        /// <param name="template">The <see cref="IUser"/> instance to use as a template</param>
        public RemoteUser(IUser template)
        {
            this.Nick = template.Nick;
            this.UserID = template.UserID;
            this.Username = template.Username;
            this.Permissions = template.Permissions;
        }

        /// <summary>
        /// Gets or Sets a reference to the client that has "discovered" this user
        /// </summary>
        public IClient Client
        {
            get { return this.client; }
            set { this.client = value; }
        }

        /// <summary>
        /// Not yet implemented
        /// </summary>
        public void Disconnect()
        {
            this.OnDisconnected(DisconnectType.UserDisconnect);
        }

        /// <summary>
        /// Called to fire the <see cref="Disconnected"/> event
        /// </summary>
        /// <param name="type">The <see cref="DisconnectType"/></param>
        private void OnDisconnected(DisconnectType type)
        {
            if (this.Disconnected != null)
                this.Disconnected.Invoke(this, new DisconnectedEventArgs(type));
        }

        /// <summary>
        /// Sends the specified packet to this user
        /// </summary>
        /// <param name="packet">The packet to send</param>
        public void Send(Packet packet)
        {
            packet.DestinationUserID = this.UserID;
            if (this.client != null)
                this.client.Send(packet);
        }

        /// <summary>
        /// Gets or Sets the Nickanme of this user
        /// </summary>
        [ProtoMember(1)]
        public string Nick
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or Sets the ID of this user
        /// </summary>
        [ProtoMember(2)]
        public int UserID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or Sets a collection of <see cref="IChannel"/>s that this user is currently in
        /// <para/>
        /// This currently always returns an empty list
        /// </summary>
        public IEnumerable<IChannel> Channels
        {
            get { return this.channels; }
            set { this.channels = new List<IChannel>(value); }
        }

        /// <summary>
        /// Fired when this user has disconnected
        /// </summary>
        public event UserDisconnected Disconnected;

        /// <summary>
        /// Gets or Sets the Username of this user
        /// </summary>
        [ProtoMember(3)]
        public string Username
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or Sets the <see cref="PermissionFlags"/> of this user
        /// </summary>
        [ProtoMember(4)]
        public PermissionFlags Permissions
        {
            get;
            set;
        }

        /// <summary>
        /// Overriden to return either the nickname or username of this user or "NONAME"
        /// </summary>
        /// <returns>Either the nickname or username of this user or "NONAME"</returns>
        public override string ToString()
        {
            return this.Nick ?? this.Username ?? "NONAME";
        }

        /// <summary>
        /// Only for storage at the moment
        /// </summary>
        public IUserInfo Info
        {
            get;
            set;
        }
    }

}